package com.ctsi.system.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ctsi.common.util.CryptoUtil;
import com.ctsi.common.util.PasswordUtil;
import com.ctsi.common.util.Search;
import com.ctsi.core.common.constant.MarsConstant;
import com.ctsi.core.common.entity.LoginEmpInfo;
import com.ctsi.core.common.entity.LoginUser;
import com.ctsi.core.common.entity.MarsDS;
import com.ctsi.core.common.enums.StatusType;
import com.ctsi.core.common.exception.MarsException;
import com.ctsi.core.common.exception.ServiceException;
import com.ctsi.core.common.util.$;
import com.ctsi.core.common.util.IPUtil;
import com.ctsi.core.common.util.RequestHolder;
import com.ctsi.core.common.util.network.UaUtil;
import com.ctsi.core.database.util.PageUtil;
import com.ctsi.core.web.checker.AdminUserChecker;
import com.ctsi.system.constant.DictConstant;
import com.ctsi.system.dto.UserInfo;
import com.ctsi.system.dto.UserPwdReqDTO;
import com.ctsi.system.dto.UserReqDTO;
import com.ctsi.system.entity.User;
import com.ctsi.system.entity.UserDataScope;
import com.ctsi.system.entity.UserRole;
import com.ctsi.system.enums.SystemExceptionEnum;
import com.ctsi.system.enums.UserExceptionEnum;
import com.ctsi.system.mapper.UserMapper;
import com.ctsi.system.service.*;
import com.ctsi.system.vo.EmpInfoResVO;
import com.ctsi.system.vo.FlowUserVO;
import com.ctsi.system.vo.UserResVO;
import com.ctsi.uaa.enums.UserType;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 系统用户表 服务实现类
 * </p>
 *
 * @author wang xiao xiang
 */
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private IUserDataScopeService userDataScopeService;
    @Autowired
    private IUserRoleService userRoleService;
    @Autowired
    private IRoleService roleService;
    @Autowired
    private IEmpService empService;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private AdminUserChecker adminUserChecker;

    @Autowired
    private IMenuService menuService;
    @Autowired
    private IAppService appService;

    @Autowired
    private IOrgService orgService;

    @Override
    public IPage<User> listPage(MarsDS marsDS, User user, Search search) {
        boolean isKeyword = $.isNotBlank(search.getKeyword());
        QueryWrapper<User> queryWrapper = Wrappers.query();
        // 多条件模糊查询
        if (isKeyword) {
            queryWrapper.and(wrapper ->
                    wrapper
                            // 查询名称
                            .like("mars_sys_user.name", search.getKeyword())
                            .or()
                            // 查询账户
                            .like("mars_sys_user.account", search.getKeyword())
                            .or()
                            // 查询手机号码
                            .like("mars_sys_user.tel", search.getKeyword()));
        }
        List<Long> orgIds = marsDS.getOrgIds();
        Long orgId = search.getOrgId();
        // 根据数据范围设置查询条件
        if ($.isNotEmpty(orgIds)) {
            queryWrapper.and(q -> q.in("mars_sys_emp.org_id", orgIds));
        }
        queryWrapper.eq($.isNotNull(user.getStatus()), "mars_sys_user.status", user.getStatus());
        queryWrapper.lambda().orderByDesc(User::getCreateTime);
        // 根据左侧点击过滤组织ID
        if ($.isNotEmpty(orgId)) {
            List<Long> subOrgList = orgService.getChildIdListWithSelfById(orgId);
            subOrgList.add(orgId);
            queryWrapper.and(q -> q.in("mars_sys_emp.org_id", subOrgList));
        }
        queryWrapper.eq("mars_sys_user.is_deleted",0);
        return this.baseMapper.page(PageUtil.getPage(search), queryWrapper);
    }


    @Override
    public UserResVO detail(Long userId) {
        // 获取系统用户
        User user = this.getById(userId);
        UserResVO userRes = $.copy(user, UserResVO.class);
        if ($.isEmpty(userRes)) {
            throw new ServiceException("用户信息为空！");
        }
        // 获取对应员工信息
        EmpInfoResVO empInfoRes = empService.getSysEmpInfo(userId);
        // 设置员工信息
        userRes.setEmpInfoRes(empInfoRes);
        return userRes;
    }

    @Override
    public List<String> getRole(User user) {
        return this.userRoleService.list(Wrappers.<UserRole>lambdaQuery()
                // 根据用户ID查询
                .eq(UserRole::getUserId, user.getId()))
                // 转换roleId为集合形式返回
                .stream().map(userRole -> $.toStr(userRole.getRoleId())).collect(Collectors.toList());
    }

    @Override
    public boolean setStatus(User user) {
        User userInfo = this.getById(user.getId());
        LoginUser loginUser = $.copy(userInfo, LoginUser.class);
        Assert.isTrue(!adminUserChecker.hasModifyPermission(loginUser), UserExceptionEnum.USER_CAN_NOT_UPDATE_ADMIN.getMessage());
        return this.update(Wrappers.<User>update().lambda()
                // 根据ID，后续可以扩展为批量更新状态
                .eq(User::getId, user.getId())
                // 更新状态
                .set(User::getStatus, user.getStatus()));
    }

    @Override
    public boolean setRole(Long userId, @RequestParam List<Long> grantRoleIdList) {
        return userRoleService.setRole(userId, grantRoleIdList);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean setUser(UserReqDTO userReq){
        User user = $.copy(userReq, User.class);
        if ($.isEmpty(user)) {
            throw new ServiceException("输入的用户信息为空！");
        }
        if ($.isEmpty(user.getId()) && $.isNotEmpty(user.getPassword())) {
            user.setPassword(passwordEncoder.encode(CryptoUtil.encodeMD5(user.getPassword())));
        }
        this.saveOrUpdate(user);
        Long userId = user.getId();
        empService.setEmpInfo(userId, userReq.getEmpInfoReq());
        return Boolean.TRUE;
    }

    @Override
    public boolean setPassword(UserPwdReqDTO userPwdReq) {
        if ($.isNotEqual(userPwdReq.getPass(), userPwdReq.getConfirmPass())) {
            throw new ServiceException("密码和确认密码不一致！");
        }
        /**
         * 准备增加验证是否有操作权限逻辑
         */
        String passwordEncrypt = PasswordUtil.decodeAesAndEncode(userPwdReq.getPass(), MarsConstant.PASSWORD_SECURITY_KEY);
        return this.update(Wrappers.<User>lambdaUpdate()
                .set(User::getPassword, passwordEncrypt)
                .eq(User::getAccount, userPwdReq.getAccount()));
    }

    @Override
    public boolean delUser(List<Long> ids) {
        ids.forEach(id -> {
            this.removeById(id);
            this.userRoleService.remove(Wrappers.<UserRole>lambdaQuery().eq(UserRole::getUserId, id));
            this.userDataScopeService.remove(Wrappers.<UserDataScope>lambdaQuery().eq(UserDataScope::getUserId, id));
        });
        return Boolean.TRUE;
    }

    @Override
    public boolean setAvatar(User user) {
        return this.updateById(user);
    }


    @Override
    public List<FlowUserVO> getFlowUserList() {
        List<User> list = this.list(Wrappers.<User>lambdaQuery().eq(User::getStatus, StatusType.ENABLE.getCode()));
        List<FlowUserVO> collect = list.stream()
                .map(user -> FlowUserVO.builder().id(user.getId().toString()).name(user.getAccount()).build())
                .collect(Collectors.toList());
        return collect;
    }

    @Override
    public UserInfo getUserInfo(User user) {
        if ($.isEmpty(user)) {
            return new UserInfo().setErrorMessage(UserExceptionEnum.USER_NOT_EXIST.getMessage());
        }
        UserInfo userInfo = new UserInfo();
        userInfo.setUser(user);
        List<Dict> roles = roleService.getLoginRoles(user.getId(),UserType.SYSTEM.getType());
        if ($.isEmpty(roles)) {
            return new UserInfo().setErrorMessage(SystemExceptionEnum.ROLE_NOT_EXIST.getMessage());
        }
        List<Long> roleList = roles.stream().map(dict -> $.toLong(dict.get(DictConstant.ID))).collect(Collectors.toList());
        // 权限信息
        List<String> permissions = menuService.getLoginPermissions(user.getId(), UserType.SYSTEM.getType());
        userInfo.setRoleIds(roleList);
        userInfo.setPermissions(permissions);
        return userInfo;
    }

    @Override
    public LoginUser getLoginUserByRequest(Long userId, HttpServletRequest request) {
        User user = this.getById(userId);
        // 构造LoginUser
        LoginUser loginUser = $.copy(user, LoginUser.class);
        if ($.isNull(loginUser)) {
            throw new MarsException(UserExceptionEnum.USER_NOT_EXIST);
        }
        if ($.isNotNull(request)) {
            loginUser.setLastLoginIp(RequestHolder.getHttpServletRequestIpAddress());
            loginUser.setLastLoginTime(DateTime.now().toString());
            loginUser.setLastLoginAddress(IPUtil.getCityInfo(loginUser.getLastLoginIp()));
            loginUser.setLastLoginOs(UaUtil.getOs(request));
            loginUser.setLastLoginBrowser(UaUtil.getBrowser(request));
            // 更新用户数据增加登录IP和登录时间
            user.setLastLoginIp(loginUser.getLastLoginIp());
            user.setLastLoginTime(LocalDateTime.now());
            updateById(user);

            // 员工信息
            LoginEmpInfo loginEmpInfo = empService.getLoginEmpInfo(userId);
            loginUser.setLoginEmpInfo(loginEmpInfo);

            // 角色信息
            List<Dict> roles = roleService.getLoginRoles(userId,UserType.SYSTEM.getType());
            loginUser.setRoles(roles);

            // 权限信息
            List<String> permissions = menuService.getLoginPermissions(userId,UserType.SYSTEM.getType());
            loginUser.setPermissions(permissions);

            // 具备应用信息（多系统，默认激活一个，可根据系统切换菜单）,返回的结果中第一个为激活的系统
            List<Dict> apps = appService.getLoginApps(userId,UserType.SYSTEM.getType());
            loginUser.setApps(apps);

            // 如果根本没有应用信息，则没有菜单信息
            if (ObjectUtil.isEmpty(apps)) {
                loginUser.setMenus(CollectionUtil.newArrayList());
            } else {
                //AntDesign菜单信息，根据人获取，用于登录后展示菜单树，默认获取默认激活的系统的菜单
                String defaultActiveAppCode = apps.get(0).getStr(DictConstant.CODE);
                loginUser.setMenus(menuService.getLoginMenusAntDesign(userId, defaultActiveAppCode,UserType.SYSTEM.getType()));
            }
            // 如果开启了多租户功能，则设置当前登录用户的租户标识
            // 待补充

        } else {
            throw new ServiceException("当前请求数据为空！");
        }
        return loginUser;
    }
}
